"""付款申请单"""

from datetime import datetime

from odoo import models, api, fields
from odoo.tools import float_compare
from odoo.exceptions import UserError, ValidationError


class Payment(models.Model):
    _name = 'purchase.payment'
    _description = "采购付款申请明细"
    _rec_name = 'purchase_id'

    partner_id = fields.Many2one('res.partner', string='供应商')
    product_id = fields.Many2one('product.product', string='产品')
    purchase_id = fields.Many2one('purchase.order', string='源单据')
    picking_id = fields.Many2one('stock.picking', string='源调拨单')
    purchase_line_id = fields.Many2one('purchase.order.line', string="原采购明细")

    taxes_id = fields.Many2many('account.tax', 'purchase_payment_tax_rel', 'payment_id',
                                'tax_id', string='税率', store=True,
                                related="purchase_line_id.taxes_id")

    state = fields.Selection([
        ("invoiced", "已申请"),
        ('not_invoiced', '未申请'),
        ('partly', '部分申请')], default="not_invoiced",
        string="请款状态", compute='update_status', store=True)

    sale_untaxed_fee = fields.Float('产品销售金额（不含税）')

    currency_id = fields.Many2one("res.currency", store=True,
                                  related='purchase_id.currency_id', string="Currency",
                                  readonly=True, required=True)

    account_payment_ids = fields.Many2many('account.payment', string="请款单")  # 这里应该断开
    purchase_request_id = fields.Many2many('purchase.request.payment')

    line_copy = fields.One2many('account.payment.line', 'origin')
    total1 = fields.Monetary(string='采购总金额', currency_field='currency_id',
                             readonly=True, compute="_compute_total", store=True)
    invoiced_amount = fields.Float('已申请总计', store=True,
                                   compute="_compute_invoice_amount", )  # 保存时更新
    uninvoiced_amount = fields.Float('未申请金额', store=True,
                                     compute="_compute_invoice_amount", )
    invoiced_qty = fields.Float('已申请数量', store=True,
                                compute="_compute_invoiced_qty")
    # invoiced_qty_done = fields.Float('已确认开票数量',
    #                                  compute="_compute_invoiced_qty_done")
    #
    # invoiced_qty_done_state = fields.Selection([("invoiced", "已开票"),
    #                                             ('not_invoiced', '未开票'),
    #                                             ('partly', '部分开票')], string='开票状态',
    #                                            compute="_compute_invoiced_qty_done", store=True)
    quantity = fields.Float('总数量')
    avg_price = fields.Float('平均单价')
    measure_unit = fields.Many2one('uom.uom', string='计量单位')
    tax_ticket_count = fields.Integer('单据数量', store=True,
                                      compute="_compute_tax_ticket")
    xdl_purchase_id = fields.Many2one('res.users', string="采购员", store=True,
                                      related="purchase_id.user_id")

    # @api.depends('purchase_line_id', 'purchase_line_id.qty_received')
    # def _compute_invoiced_qty_done(self):
    #     for line in self:
    #         ticket_line = self.env['purchase.payment'].search(
    #             [('purchase_line_id', '=', line.purchase_line_id.id)])
    #         invoiced_qty = sum(ticket_line.mapped('invoiced_qty_done'))
    #         line.invoiced_qty_done = invoiced_qty
    #         if invoiced_qty <= 0:
    #             line.invoiced_qty_done_state = 'not_invoiced'
    #         elif invoiced_qty >= line.purchase_line_id.qty_received:
    #             line.invoiced_qty_done_state = 'invoiced'
    #         else:
    #             line.invoiced_qty_done_state = 'partly'

    @api.depends('invoiced_amount', 'total1')
    def update_status(self):
        for order in self:
            if 0 < order.invoiced_amount < order.total1:
                order.state = 'partly'
            elif order.invoiced_amount >= order.total1:
                order.state = 'invoiced'
            else:
                order.state = 'not_invoiced'

    @api.depends('line_copy.purchase_request_payment', 'total1',
                 'line_copy.purchase_request_payment.state',
                 'purchase_request_id')
    def _compute_invoice_amount(self):
        for order in self:
            amount = 0
            active_records = order.line_copy.filtered(lambda x: x.purchase_request_payment.state and
                                                                x.purchase_request_payment.state != 'cancelled')
            for copy in active_records:
                amount += copy.this_amount
            order.update({'invoiced_amount': amount,
                          'uninvoiced_amount': order.total1 - amount})

    @api.depends('line_copy.this_quatity')
    def _compute_invoiced_qty(self):
        for order in self:
            qty = 0
            for copy in order.line_copy.filtered(
                    lambda x: x.purchase_request_payment and x.purchase_request_payment.state != 'cancelled'):
                qty += copy.this_quatity
            order.invoiced_qty = qty

    @api.depends('purchase_request_id')
    def _compute_tax_ticket(self):
        for order in self:
            order.tax_ticket_count = len(order.purchase_request_id)

    @api.multi
    def action_view_tax_ticket(self):
        form_view_id = self.env.ref('nd_purchase_payment.purchase_request_payment_form_view').id
        tree_view_id = self.env.ref('nd_purchase_payment.purchase_request_payment_tree_view').id
        action = {
            'type': 'ir.actions.act_window',
            'views': [(tree_view_id, 'tree'), (form_view_id, 'form')],
            'view_mode': 'tree,form',
            'name': '请款单',
            'res_model': 'purchase.request.payment',
            # 'context': dict(self.env.context, is_taxed=self.is_taxed, search_default_group_product=True),
            'domain': [('id', 'in', self.purchase_request_id.ids)]
        }
        return action


class PurchaseRequestPayment(models.Model):
    _name = 'purchase.request.payment'
    _inherit = ['mail.thread', 'common.state.methods']
    _order = 'id desc'
    _description = "采购付款申请单"

    name = fields.Char('编号', readonly=True, copy=False)
    account_payment_line = fields.One2many('account.payment.line', 'purchase_request_payment')
    # request_lines = fields.Many2many('request.tax.ticket.line') # TODO ??
    # payment_type = fields.Many2one('request.payment.type', string="付款方式")
    payment_type_ids = fields.One2many('purchase.request.payment.detail',
                                       'purchase_request_payment_id', '付款方式')
    tax = fields.Boolean('是否含税', compute="_compute_tax", store=True)

    request_user = fields.Many2one('res.users', string="申请员工")
    partner_id = fields.Many2one('res.partner', string="合作伙伴")
    currency_id = fields.Many2one('res.currency', string='Currency', required=True,
                                  default=lambda self: self.env.user.company_id.currency_id)
    amount = fields.Monetary(string='付款总额',  currency_field='currency_id',
                             compute="_compute_amount", store=True)

    payment_date = fields.Date('付款日期')
    request_date = fields.Date('请款日期', default=lambda self: datetime.now().date())
    discription = fields.Char('备注')
    user_account_name = fields.Char('用户名')
    user_bank_name = fields.Char('开户行')
    user_bank_account = fields.Char('卡号')

    state = fields.Selection([
        ('ready', '草稿'),
        ('draft', '部门经理审核'),
        ('financial_approve', '财务审核'),
        ('payment_approve', '出纳提交'),
        ('boss_approve', '领导审核'),
        ('done', '完成'),
        ('cancelled', '取消')],  default='ready',
        copy=False, string="状态", track_visibility="onchange")

    def get_unique_name(self):
        if not self.name:
            self.name = self.env['ir.sequence'].next_by_code('purchase.request.payment.name')

    @api.depends('account_payment_line.taxes_id')
    def _compute_tax(self):
        for order in self:
            for copy in order.account_payment_line:
                if copy.taxes_id:
                    order.tax = True
                    return
            order.tax = False

    @api.depends('account_payment_line.this_amount')
    def _compute_amount(self):
        for order in self:
            amount = 0
            for line in order.account_payment_line:
                amount += line.this_amount
            order.amount = order.currency_id.round(amount)

    def constraint_amount(self):
        # 检查付款情况：付款方式明细的总额 = 付款总金额
        line_total = sum(self.payment_type_ids.mapped('amount'))
        if line_total != self.amount:
            raise UserError(f'付款方式明细的总额应该是：{self.amount}')

    @api.multi
    def cancel(self):
        self.write({'state': 'cancelled'})

    @api.multi
    def submit(self):
        self.ensure_one()
        self.constraint_amount()  # 检查金额限制
        self.get_unique_name()  # 获取名称
        if self.state == 'ready':
            self.state = 'draft'

    @api.multi
    def submit_to_approval(self):
        self.ensure_one()
        if self.state == 'draft':
            self.state = 'financial_approve'

    @api.multi
    def financial_approve(self):
        if self.state == 'financial_approve':
            self.state = 'payment_approve'

    @api.multi
    def payment_approve(self):
        if self.state == 'payment_approve':
            self.state = 'boss_approve'

    @api.multi
    def boss_approve(self):
        self.ensure_one()
        if self.state == 'boss_approve':
            self.write({
                'state': 'done',
                'payment_date': datetime.now().date()
            })
            self._create_bank_statement_line(self)
            # if self.money_rebate_amount:
            #     self._create_account_move()

    @api.model
    def _create_bank_statement_line(self, payment_requests):
        """
        根据请款单明细创建银行日记账明细
        :param payment_requests: purchase.request.payment，请款单
        :return:
        """
        STATEMENT = self.env['account.bank.statement.line']
        for payment_request in payment_requests:
            for line in payment_request.payment_type_ids:
                STATEMENT.create_statement_line_from_payment_request(line.payment_type,
                                                                     payment_request.request_date,
                                                                     payment_request.partner_id,
                                                                     line.amount,
                                                                     payment_request.name)

    # def _create_account_move(self):
    #     # 如果采购请款单上有返利金额，则创建等额的日记账分录
    #     account = self.env['purchase.rebate.account.setting'].search([])
    #     if account:
    #         account = account[0]
    #     else:
    #         raise UserError('没有找到采购返利日记账的科目配置，请先在“采购/配置”菜单下配置')
    #     # 借方参数
    #     debit_vals = {
    #         'account_id':account.credit_account_id.id,
    #         'partner_id':self.partner_id.id,
    #         'name':'返利',
    #         'debit':self.money_rebate_amount
    #         }
    #
    #     # 贷方参数
    #     credit_vals = {
    #         'account_id': account.debit_account_id.id,
    #         'partner_id': self.partner_id.id,
    #         'name': '返利',
    #         'credit': self.money_rebate_amount
    #         }
    #
    #     vals = {
    #         'date': datetime.now(),
    #         'journal_id':self._get_journal_id(),
    #         'line_ids':[(0, 0, debit_vals), (0, 0, credit_vals)]
    #         }
    #
    #     move = self.env['account.move'].create(vals)
    #     self.account_move_id = move.id

    # def _get_journal_id(self):
    #     # 获取“返利日记账”类，一般此类是提前自动写入，如果没有则提醒创建。
    #     journal = self.env['account.journal'].search([('code', '=', 'FL')])
    #     if not journal:
    #         raise UserError('没有找到“返利日记账”类，请创建一个，并确保简码为FL！')
    #     return journal[0].id

    @api.multi
    def action_view_account_move(self):
        form_view_id = self.env.ref('account.view_move_form').id
        tree_view_id = self.env.ref('account.view_move_tree').id
        action = {
            'type': 'ir.actions.act_window',
            'views': [(tree_view_id, 'tree'), (form_view_id, 'form')],
            'view_mode': 'tree,form',
            'name': '返利日记账分录',
            'res_model': 'account.move',
            # 'context': dict(self.env.context, is_taxed=self.is_taxed, search_default_group_product=True),
            'domain':[('id', '=', self.account_move_id.id)]
            }
        return action


class PaymentType(models.Model):
    _name = 'purchase.request.payment.detail'
    _description = "采购请款的付款方式明细"

    payment_type = fields.Many2one('account.journal', string="付款方式")
    amount = fields.Float('付款金额')
    purchase_request_payment_id = fields.Many2one('purchase.request.payment', string="请款单")


class RequestPaymentType(models.Model):
    _name = 'request.payment.type'
    _description = "采购请款的付款方式配置"

    name = fields.Char('名称')
    tax = fields.Boolean('含税的付款方式')


class AccountPaymentLine(models.Model):
    _name = 'account.payment.line'

    origin = fields.Many2one('purchase.payment')
    account_payment_id = fields.Many2one('account.payment') # 这里应该断开
    purchase_request_payment = fields.Many2one('purchase.request.payment', ondelete="cascade")
    purchase_id = fields.Many2one('purchase.order', related='origin.purchase_id',
                                  string='Purchase Order', store=False, related_sudo=False)
    purchase_line_id = fields.Many2one('purchase.order.line', related='origin.purchase_line_id',
                                       ondelete='set null', index=True)
    product_id = fields.Many2one('product.product', string="产品",
                                 related="origin.product_id", store=True)
    quantity = fields.Float('总数', related="origin.quantity", store=True)
    price = fields.Float('单价', related="origin.avg_price", store=True)
    taxes_id = fields.Many2many('account.tax', string='税金', domain=['|', ('active', '=', False), ('active', '=', True)],
                                related="purchase_line_id.taxes_id")
    currency_id = fields.Many2one(related='purchase_id.currency_id', store=True, string='Currency', readonly=True)
    # subtotal = fields.Monetary('小计', store=True, related="origin.purchase_line_id.price_subtotal")
    # price_tax = fields.Monetary('税金', store=True, related="origin.purchase_line_id.price_tax")
    measure_unit = fields.Many2one('uom.uom', string='计量单位',
                                   related="origin.measure_unit", store=True)
    total = fields.Monetary('总额', store=True, related="origin.total1" )
    requested_amount = fields.Float('已请款总额', related="origin.invoiced_amount", store=True)
    # invoiced_qty_done = fields.Float('已确认开票数量', compute="_compute_invoiced_qty_done")

    this_amount = fields.Float('本次请款金额')
    this_quatity = fields.Float('数量', compute="_compute_this_quatity", store=True)
    delivered_qty = fields.Float('已收货数量', related="purchase_line_id.qty_received", store=True)
    additional_note = fields.Char('备注')

    # def _compute_invoiced_qty_done(self):
    #     # 通过采购明细行来找到与此请款单对应的发票明细，收集发票明细的已开票数量
    #     for order in self:
    #         ticket_line = self.env['purchase.payment'].search([
    #             ('purchase_line_id', '=', order.purchase_line_id.id)])
    #         invoiced_done = sum(ticket_line.mapped('invoiced_qty_done'))
    #         order.invoiced_qty_done = invoiced_done

    @api.depends('this_amount', 'price')
    def _compute_this_quatity(self):
        for order in self:
            if order.price:
                order.this_quatity = order.this_amount / order.price

    @api.constrains('this_amount', 'requested_amount')
    def _constrain_this_amount(self):
        for order in self:
            if order.requested_amount > order.total:
                raise ValidationError('明细的已请款总额%s大于总额%s！'%(order.requested_amount, order.total))


class AccountStatementLineExtend(models.Model):
    _inherit = 'account.bank.statement.line'


    @api.model
    def create_statement_line_from_payment_request(self, journal_id, request_date, partner_id, amount, request_name):
        """根据请款单创建银行日记账"""
        # 根据日记账和日期来定位银行日记账
        statement_id = self.env['account.bank.statement'].search([('journal_id', 'in', journal_id.ids),
                                                                  ('date', '>=', request_date)], order="date", limit=1)
        statement_class_id = self.env['account.statement.line.class'].search([('account_id.code', '=', '2202.02'),
                                                                              ('used', '=', 'credit')], limit=1)
        if statement_id:
            data = {
                'statement_id': statement_id.id,
                'date': request_date,
                'name': f'{request_name}-请款',
                'partner_id': partner_id.id,
                'line_partner_type': 'supplier',
                'statement_class': statement_class_id.id,
                'amount': amount
            }
            return self.create(data)
        else:
            raise UserError(f'没有找到{journal_id.display_name}在日期{request_date}期间的银行日记账！')

